//
//  UIViewController+RSCameraOrLibrary.m
//  RSSceneEvidenceTest
//
//  Created by thinkjoy on 2017/8/21.
//  Copyright © 2017年 杜瑞胜. All rights reserved.
//

#import "UIViewController+RSCameraOrLibrary.h"
#import "objc/runtime.h"
#import <AssetsLibrary/ALAssetsLibrary.h>
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#import <Photos/Photos.h>

#import <CoreGraphics/CoreGraphics.h>
#import <AssetsLibrary/AssetsLibrary.h>
#import <MobileCoreServices/UTCoreTypes.h>

#ifdef DEBUG
#define debugLog(...)    NSLog(__VA_ARGS__)
#else
#define debugLog(...)
#endif

static  BOOL canEdit    = NO;
static  char blockInfoKey;
static  BOOL isSave = NO;

typedef void(^AlertViewAction)(UIAlertAction *action);
typedef void(^AlertViewOtherAction)(UIAlertAction *action);

//视频最大长度
static const NSInteger  VideoMaximumDuration    =   30*60;

@interface UIViewController()<UIActionSheetDelegate,UINavigationControllerDelegate, UIImagePickerControllerDelegate,UIAlertViewDelegate>

@property   (nonatomic,copy)CameraOrLibraryBlock phoneInfoBlock;

@end

@implementation UIViewController (RSCameraOrLibrary)

#pragma mark-set
- (void)setPhoneInfoBlock:(CameraOrLibraryBlock)phoneInfoBlock
{
    objc_setAssociatedObject(self, &blockInfoKey, phoneInfoBlock, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

#pragma mark-get
- (CameraOrLibraryBlock)phoneInfoBlock
{
    return objc_getAssociatedObject(self, &blockInfoKey);
}

- (void)showCanEdit:(BOOL)edit saveInLibrary:(BOOL)isSave photoType:(RSCameraOrLibraryType)type  photoInfoBlock:(CameraOrLibraryBlock)block
{
    canEdit =   edit;
    isSave  =   isSave;
    self.phoneInfoBlock = [block copy];
    
    UIAlertController *alertC = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
    //使用相薄
    if (type&RSCameraOrLibraryType_LibraryPhoto || type&RSCameraOrLibraryType_LibraryVideo) {
        //相薄+相机
        if (type&RSCameraOrLibraryType_CameraPhoto || type&RSCameraOrLibraryType_CameraVideo) {
            UIAlertAction *alertOne = [UIAlertAction actionWithTitle:@"打开相薄" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action)  {
                [self    clickActionWithButtonIndex:1 photoType:type];
            }];
            UIAlertAction *alertTwo = [UIAlertAction actionWithTitle:@"打开相机" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action)  {
                [self    clickActionWithButtonIndex:0 photoType:type];
            }];
            UIAlertAction *alertThree = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action)  {
                
            }];
            [alertC addAction:alertOne];
            [alertC addAction:alertTwo];
            [alertC addAction:alertThree];
            [[[UIApplication sharedApplication] keyWindow].rootViewController presentViewController:alertC animated:YES completion:nil];
        }
        //只打开相薄
        else{
            [self    clickActionWithButtonIndex:1 photoType:type];
        }
    }
    //只打开相机
    else{
        [self    clickActionWithButtonIndex:0 photoType:type];
    }
}

#pragma mark    - 根据索引检测是否有授权
- (BOOL)isAuthWithButtonIndex:(NSInteger )buttonIndex
{
    BOOL isAuth =   YES;
    //相机
    if (buttonIndex==0) {
        //相机权限
        AVAuthorizationStatus cameraStatus  =   [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
        if (cameraStatus ==AVAuthorizationStatusRestricted || cameraStatus== AVAuthorizationStatusDenied) {
            isAuth  =   NO;
        }
    }else{
        //相薄权限
        PHAuthorizationStatus   libraryStatus  =     [PHPhotoLibrary authorizationStatus];
        if (libraryStatus==PHAuthorizationStatusRestricted || libraryStatus==PHAuthorizationStatusDenied) {
            isAuth  =   NO;
        }
    }
    return isAuth;
}

- (void)clickActionWithButtonIndex:(NSInteger )buttonIndex photoType:(RSCameraOrLibraryType)type
{
    if (![self isAuthWithButtonIndex:buttonIndex]) {
        [self showAlertViewWithControllerTitle:nil message:[NSString stringWithFormat:@"还没有开启%@权限,请在系统设置中开启",buttonIndex==0?@"相机":@"相薄"] controllerStyle:UIAlertControllerStyleAlert isHaveTextField:NO actionTitle:@"暂不" actionStyle:UIAlertActionStyleCancel alertViewAction:^(UIAlertAction *action) {
            
        } otherActionTitle:@"去设置" otherActionStyle:UIAlertActionStyleDefault otherAlertViewAction:^(UIAlertAction *action) {
            //跳转到设置界面
            if([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]) {
                if ([[[UIDevice currentDevice] systemVersion] floatValue]<10) {

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
                    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
#pragma clang diagnostic pop
                    
                }else{
                    
                    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil];
                }
                
            }
        }];
        return;
    }
    
    //跳转到相机/相薄页面
    UIImagePickerController* imagePickerController = [[UIImagePickerController alloc] init];
    imagePickerController.delegate = self;
    imagePickerController.allowsEditing = canEdit;
    
    //相机
    if (buttonIndex==0) {
        //是否支持相机
        if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
        {
            imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
            
            NSMutableArray * mediaTypesMuAry    =   [NSMutableArray array];
            if (type&RSCameraOrLibraryType_CameraVideo) {
                [mediaTypesMuAry addObject:(NSString *)kUTTypeMovie];
                imagePickerController.videoMaximumDuration = VideoMaximumDuration; //视频最大长度
            }
            if (type&RSCameraOrLibraryType_CameraPhoto) {
                [mediaTypesMuAry addObject:(NSString *)kUTTypeImage];
            }
            
            imagePickerController.mediaTypes    =   mediaTypesMuAry;
            
            [self presentViewController:imagePickerController animated:YES completion:NULL];
        }
        else
        {
            [self  showAlertViewWithControllerTitle:@"温馨提示" message:@"该设备不支持相机" controllerStyle:UIAlertControllerStyleAlert isHaveTextField:NO actionTitle:@"确定" actionStyle:UIAlertActionStyleCancel alertViewAction:^(UIAlertAction *action) {
                
            }];
        }
        
    }
    //相薄
    else{
        imagePickerController.sourceType =UIImagePickerControllerSourceTypePhotoLibrary;
        NSMutableArray * mediaTypesMuAry    =   [NSMutableArray array];
        if (type&RSCameraOrLibraryType_LibraryVideo) {
            [mediaTypesMuAry addObject:(NSString *)kUTTypeMovie];
        }
        if (type&RSCameraOrLibraryType_LibraryPhoto) {
            [mediaTypesMuAry addObject:(NSString *)kUTTypeImage];
        }
        imagePickerController.mediaTypes    =   mediaTypesMuAry;
        [self presentViewController:imagePickerController animated:YES completion:NULL];
    }
}

#pragma mark - image picker delegte
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
{
    NSString *mediaType = info[UIImagePickerControllerMediaType];
    //图片
    if ([mediaType isEqualToString:(NSString *)kUTTypeImage]){
        NSURL *imageURL = [info valueForKey:UIImagePickerControllerReferenceURL];
        NSString* ext = imageURL.pathExtension.lowercaseString;
        if ([ext isEqualToString:@"gif"]) {
            //            [self saveGifToDocument:imageURL];
            NSLog(@"GIF图");
        } else {
            UIImage *image;
            //是否要裁剪
            if ([picker allowsEditing]){
                //编辑之后的图像
                image = [info objectForKey:UIImagePickerControllerEditedImage];
            } else {
                image = [info objectForKey:UIImagePickerControllerOriginalImage];
            }
            
                
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
                
            ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init];
            //根据url获取asset信息, 并通过block进行回调
            [assetsLibrary assetForURL:imageURL resultBlock:^(ALAsset *asset) {
                ALAssetRepresentation *representation = [asset defaultRepresentation];
                NSString *imageName = representation.filename;
                NSLog(@"imgUrl=%@;imageName:%@",imageURL, imageName);
                
                NSDictionary *imageDic;
                if (imageName.length) {
                    imageDic = [self saveToDocument:image imageName:imageName];
                }else{
                    imageDic = [self saveToDocument:image imageName:nil];
                }
                
                if (self.phoneInfoBlock) {
                    self.phoneInfoBlock(imageDic);
                }
            } failureBlock:^(NSError *error) {
                NSLog(@"%@", [error localizedDescription]);
            }];
#pragma clang diagnostic pop
        }
    }
    //视频
    else if ([mediaType isEqualToString:(NSString *)kUTTypeMovie]) {
        NSURL *videoURL = info[UIImagePickerControllerMediaURL];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init];
        //根据url获取asset信息, 并通过block进行回调
        [assetsLibrary assetForURL:info[UIImagePickerControllerReferenceURL] resultBlock:^(ALAsset *asset) {
            ALAssetRepresentation *representation = [asset defaultRepresentation];
            NSString *videoName;
            if (representation.filename.length) {
                videoName   =   [[representation.filename componentsSeparatedByString:@"."] firstObject];
            }
            NSDictionary * videoDic =   [self convertToMp4:videoURL videoName:videoName];
            
            NSFileManager *fileman = [NSFileManager defaultManager];
            if ([fileman fileExistsAtPath:videoURL.path]) {
                NSError *error = nil;
                [fileman removeItemAtURL:videoURL error:&error];
                if (error) {
                    NSLog(@"failed to remove file, error:%@.", error);
                }
            }
            
            if (self.phoneInfoBlock) {
                self.phoneInfoBlock(videoDic);
            }
        } failureBlock:^(NSError *error) {
            NSLog(@"%@", [error localizedDescription]);
        }];
#pragma clang diagnostic pop
    }
    [picker dismissViewControllerAnimated:YES completion:nil];
}

- (PHAssetCollection *)getCurrentPhotoCollectionWithTitle:(NSString *)collectionName {
    // 1. 创建搜索集合
    PHFetchResult *result = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
    // 2. 遍历搜索集合并取出对应的相册
    for (PHAssetCollection *assetCollection in result){
        if ([assetCollection.localizedTitle containsString:collectionName]) {
            return assetCollection;
        }
    }
    return nil;
}
    
#pragma mark    - 保存图片到沙盒
-(NSDictionary*)saveToDocument:(UIImage*)image imageName:(NSString *)imageName
{
    UIImage* fixImage = [self fixOrientation:image];
    
    NSString* fileName;
    if (imageName) {
        fileName    =   imageName;
    }else{
        NSDateFormatter* formater = [[NSDateFormatter alloc] init];
        //强制设置为英文环境，适配中文（真机）环境下也能正常转换
        [formater setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US"]];
        [formater setDateFormat:@"图片yyyyMMddHHmmssSSS"];
        
        fileName    =   [NSString stringWithFormat:@"%@.png", [formater stringFromDate:[NSDate date]]];
        //保存图片到相薄
         if (isSave) {
             UIImageWriteToSavedPhotosAlbum(fixImage, self, @selector(image:didFinishSavingWithError:contextInfo:), (__bridge void *)self);
         }
    }
//    NSString* filePath=[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:fileName];
    
//    //图片按0.5的质量压缩－》转换为NSData
//    NSData *imageData = UIImageJPEGRepresentation(fixImage, 0.5);
//    [imageData writeToFile:filePath atomically:YES];
    
    
    return @{RSCameraOrLibraryFileType:(NSString *)kUTTypeImage,
             RSCameraOrLibraryImage:fixImage,
             RSCameraOrLibraryImageName:fileName,
             RSCameraOrLibraryFileDate:[NSDate date],
             };
}
#pragma mark    保存图片到相册
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
    NSLog(@"image = %@, error = %@, contextInfo = %@", image, error, contextInfo);
}

#pragma mark    保存音视频文件
- (NSDictionary *)convertToMp4:(NSURL *)movUrl videoName:(NSString *)name
{
    NSURL *mp4Url = nil;
    AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:movUrl options:nil];
    
    NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];
    NSString* fileName;
    
    if ([compatiblePresets containsObject:AVAssetExportPreset640x480]) {
        AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:avAsset
                                                                               presetName:AVAssetExportPreset640x480];
        
        if (name) {
            fileName    =   [NSString stringWithFormat:@"%@.mp4", name];
        }else{
            NSDateFormatter* formater = [[NSDateFormatter alloc] init];
            //强制设置为英文环境，适配中文（真机）环境下也能正常转换
            [formater setLocale:[NSLocale localeWithLocaleIdentifier:@"en_US"]];
            [formater setDateFormat:@"录像yyyyMMddHHmmssSSS"];
            fileName = [NSString stringWithFormat:@"%@.mp4", [formater stringFromDate:[NSDate date]]];
        }
        NSString* path = [NSString stringWithFormat:@"file:///private%@",[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:fileName]];
        mp4Url = [NSURL URLWithString:[path stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]]];
        
        exportSession.outputURL = mp4Url;
        exportSession.shouldOptimizeForNetworkUse = YES;
        exportSession.outputFileType = AVFileTypeMPEG4;
        dispatch_semaphore_t wait = dispatch_semaphore_create(0);
        [exportSession exportAsynchronouslyWithCompletionHandler:^{
            switch ([exportSession status]) {
                case AVAssetExportSessionStatusFailed: {
                    NSLog(@"failed, error:%@.", exportSession.error);
                } break;
                case AVAssetExportSessionStatusCancelled: {
                    NSLog(@"cancelled.");
                } break;
                case AVAssetExportSessionStatusCompleted: {
                    NSLog(@"completed.");
                } break;
                default: {
                    NSLog(@"others.");
                } break;
            }
            dispatch_semaphore_signal(wait);
        }];
        
        long timeout = dispatch_semaphore_wait(wait, DISPATCH_TIME_FOREVER);
        if (timeout) {
            NSLog(@"timeout.");
        }
        
        if (wait) {
            wait = nil;
        }
    }
    
    if (!name) {
        if (isSave) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
            ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
            [library writeVideoAtPathToSavedPhotosAlbum:mp4Url completionBlock:^(NSURL *assetURL, NSError *error) {
                
            }];
#pragma clang diagnostic pop
        }
    }
    
    return @{RSCameraOrLibraryFileType:(NSString *)kUTTypeMovie,
             RSCameraOrLibraryVideoName:fileName,
             RSCameraOrLibraryVideoPath:[mp4Url relativePath]};
}
#pragma mark    - 只有一个action
/**
 *  创建一个只有一个action
 */
- (void)showAlertViewWithControllerTitle:(NSString *)controllerTitle
                                 message:(NSString *)message
                         controllerStyle:(UIAlertControllerStyle)controllerStyle
                         isHaveTextField:(BOOL)isHaveTextField
                             actionTitle:(NSString *)actionTitle
                             actionStyle:(UIAlertActionStyle)actionStyle
                         alertViewAction:(AlertViewAction)alertViewAction {
    
    UIAlertController *alertC = [UIAlertController alertControllerWithTitle:controllerTitle message:message preferredStyle:controllerStyle];
    if (isHaveTextField == YES) {
        [alertC addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
            
        }];
    }
    UIAlertAction *alertOne = [UIAlertAction actionWithTitle:actionTitle style:actionStyle handler:^(UIAlertAction * _Nonnull action)  {
        alertViewAction(action);
    }];
    [alertC addAction:alertOne];
    
    [[[UIApplication sharedApplication] keyWindow].rootViewController presentViewController:alertC animated:YES completion:nil];
}

#pragma mark    创建一个有二个action
/**
 *  创建一个有二个action
 */
- (void)showAlertViewWithControllerTitle:(NSString *)controllerTitle
                                 message:(NSString *)message
                         controllerStyle:(UIAlertControllerStyle)controllerStyle
                         isHaveTextField:(BOOL)isHaveTextField
                             actionTitle:(NSString *)actionTitle
                             actionStyle:(UIAlertActionStyle)actionStyle
                         alertViewAction:(AlertViewAction)alertViewAction
                        otherActionTitle:(NSString *)otherActionTitle
                        otherActionStyle:(UIAlertActionStyle)otherActionStyle
                    otherAlertViewAction:(AlertViewOtherAction)otherAlertViewAction
{
    UIAlertController *alertC = [UIAlertController alertControllerWithTitle:controllerTitle message:message preferredStyle:controllerStyle];
    if (isHaveTextField == YES) {
        [alertC addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
            
        }];
    }
    UIAlertAction *alertOne = [UIAlertAction actionWithTitle:actionTitle style:actionStyle handler:^(UIAlertAction * _Nonnull action)  {
        alertViewAction(action);
    }];
    UIAlertAction *alertTwo = [UIAlertAction actionWithTitle:otherActionTitle style:otherActionStyle handler:^(UIAlertAction * _Nonnull action)  {
        otherAlertViewAction(action);
    }];
    [alertC addAction:alertOne];
    [alertC addAction:alertTwo];
    
    [[[UIApplication sharedApplication] keyWindow].rootViewController presentViewController:alertC animated:YES completion:nil];
}

#pragma mark    - 检测图片的orientation属性,转为0
- (UIImage *)fixOrientation:(UIImage *)aImage {
    
    // No-op if the orientation is already correct
    if (aImage.imageOrientation == UIImageOrientationUp)
        return aImage;
    
    // We need to calculate the proper transformation to make the image upright.
    // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
    CGAffineTransform transform = CGAffineTransformIdentity;
    
    switch (aImage.imageOrientation) {
        case UIImageOrientationDown:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, aImage.size.width, aImage.size.height);
            transform = CGAffineTransformRotate(transform, M_PI);
            break;
            
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
            transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
            transform = CGAffineTransformRotate(transform, M_PI_2);
            break;
            
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, 0, aImage.size.height);
            transform = CGAffineTransformRotate(transform, -M_PI_2);
            break;
        default:
            break;
    }
    
    switch (aImage.imageOrientation) {
        case UIImageOrientationUpMirrored:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;
            
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, aImage.size.height, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;
        default:
            break;
    }
    
    // Now we draw the underlying CGImage into a new context, applying the transform
    // calculated above.
    CGContextRef ctx = CGBitmapContextCreate(NULL, aImage.size.width, aImage.size.height,
                                             CGImageGetBitsPerComponent(aImage.CGImage), 0,
                                             CGImageGetColorSpace(aImage.CGImage),
                                             CGImageGetBitmapInfo(aImage.CGImage));
    CGContextConcatCTM(ctx, transform);
    switch (aImage.imageOrientation) {
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            // Grr...
            CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.height,aImage.size.width), aImage.CGImage);
            break;
            
        default:
            CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.width,aImage.size.height), aImage.CGImage);
            break;
    }
    
    // And now we just create a new UIImage from the drawing context
    CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
    UIImage *img = [UIImage imageWithCGImage:cgimg];
    CGContextRelease(ctx);
    CGImageRelease(cgimg);
    return img;
}
@end

